/** @file    EncoderProtocol.cpp
 *  @author  Alessandro Polo
 *  @version $Id: EncoderProtocol.cpp 2829 2010-08-02 20:45:47Z alex $
 *  @brief
 * File containing methods for the wosh::EncoderProtocol class.
 * The header for this class can be found in EncoderProtocol.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/
 
 #include <core/EncoderProtocol.h>

 #include <core/ObjectFactory.h>
 #include <core/PersistenceManager.h>
 #include <core/MessageProcessingCommon.h>
 #include <core/MethodsCommon.h>
 #include <core/Utilities.h>
 #include <core/DataModels.h>
 #include <core/List.h>


using namespace std;
namespace wosh {


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_REGISTER_INTERFACE(wosh::EncoderBase, "", 1.00, _static_EncoderBase )

DataFieldCollector<EncoderBase>* EncoderBase::getDataFields() {
	DataFieldCollector<EncoderBase>* fields = new DataFieldCollector<EncoderBase>();
	fields->add<const char*,Variant>(&EncoderBase::getClassName, "Type", 0);
	fields->add<const char*,Variant>(&EncoderBase::getMappedObject, "MappedObject", 1);
	return fields;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_REGISTER_INTERFACE(wosh::EncoderProtocol, "", 1.00, _static_EncoderProtocol )

EncoderProtocol::EncoderProtocol()
	: Object( PersistenceManager::getInstance() ) {
	Object::setName("EncoderProtocol", Utilities::randomLong() );
	Object::getURI().setName( Object::getName() );
	this->listener = NULL;
	this->initialized = false;

	Log.setIndent( 3 );
	Log.setContext( Object::getName() );
	Log.setLevel( LOG_INFO );
//Log.setLevel( LOG_VERBOSE );

	Log(LOG_DEBUG, " Settings Properties.." );
	Properties.set( _EncoderProtocol_KEY_ProtocolPrefix,	"",	Permission(Permission::Read) );
	Properties.set( _EncoderProtocol_KEY_ProtocolVersion,	0.0, Permission(Permission::Read) );
	Properties.set( _EncoderProtocol_KEY_Priority,			0, Permission::RW_RW_R__() );
	Properties.updateObjectKeys(this);
	Properties.setPropertiesProviderListener(this);

	Log(LOG_DEBUG, " Registering Methods.." );
	Methods.setPermission( Object::getPermission(), Permission::Overwrite_All, true, true );
	Methods.getListPermission().setMask( Permission::Read, Permission::Read, Permission::Read );

	MethodPropertyT::createMethods( &Methods, &Properties, &Log );

	MethodChT::createMethods( &Methods, this, &Properties, &Log );

	MethodList* mmListMethods = Methods.create<MethodList>( _METHOD_ListMethods, "List Methods", Permission(Permission::RX) );
	mmListMethods->setDataFieldExtractor( DataFieldExtractor<Method>::createFor< DataAdapterMapT<std::string,Method> >(Methods, "EncoderProtocol Methods") );

 }

EncoderProtocol::~EncoderProtocol() {
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT EncoderProtocol::init() {
	if ( this->initialized ) return WRET_ERR_ILLEGAL_USE;
	Object::getURI().setName( Object::getName() );
	Log.setContext( Object::getName() );

	Properties.transactionBeginWrite();
	Properties.update( _EncoderProtocol_KEY_ProtocolPrefix, getProtocol() );
	Properties.update( _EncoderProtocol_KEY_ProtocolVersion, getProtocolVersion() );
	Properties.transactionEnd();

	MethodList* mmListEncoderBase = Methods.create<MethodList>( _METHOD_List, "List Encoders", Permission::R_XR_XR__() );
	mmListEncoderBase->setDataFieldExtractor( DataFieldExtractor<EncoderBase>::createFor< DataAdapterMapT<ObjectTypeInfo, EncoderBase> >(this->getEncodersBase(), "Encoders") );

	this->initialized = true;

	return WRET_OK;
 }


WRESULT EncoderProtocol::setListener( IEncoderProtocolListener* enc_listener ) {
	this->listener = enc_listener;
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////// PROPERTY EVENTS

bool EncoderProtocol::updatingProperty( bool& , const Variant& , Property& , const PropertiesProvider* ) {
	return true;
 }

///////////////////////////////////////////////////////////////////////////////////////////// PROPERTY EVENTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

DataFieldCollector<EncoderProtocol>* EncoderProtocol::getDataFields() {
	DataFieldCollector<EncoderProtocol>* fields = new DataFieldCollector<EncoderProtocol>();
	fields->add<const std::string&, Variant>(&EncoderProtocol::getName, "Name", 0);
	fields->add<const char*,Variant>(&EncoderProtocol::getClassName, "Type", 1);
	fields->add<const char*,Variant>(&EncoderProtocol::getProtocol, "ProtocolPrefix", 2);
	fields->add<const std::string&,Variant>(&EncoderProtocol::getEntityID, "EntityID", 5, false);
	fields->add<const URI&,URI>(&EncoderProtocol::getURI, "URI", 6, false);
	fields->add<const Permission&,Permission>(&EncoderProtocol::getPermission, "Permission", 7, false);
	return fields;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool EncoderProtocol::isSupported( const char* classname, double version) const {
	ObjectTypeInfo info(classname, "", version, true);
	return getEncodersBase().exists(info);
 }

int64 EncoderProtocol::serializeTo( const ISerializable* object, char* buffer, int64 buffer_size, int encoder_options ) {
	if ( object == NULL || buffer == NULL ) return -1;
	getEncodersBase().transactionBeginRead();
	EncoderBase* enc = selectEncoder_(getEncodersBase(), object->getClassName());
	if ( enc == NULL ) {
		getEncodersBase().transactionEnd();
		Log(LOG_CRITICAL, ":serializeTo(%s, %"PRId64") FAILED: Encoder not found!", object->getClassName());
		return WRET_ERR_ILLEGAL_USE;
	 }
	int64 ret = enc->serializeTo(object, buffer, buffer_size, encoder_options);
	if ( Log.isDebug() )
		Log(LOG_DEBUG, ":serializeTo(%s, %"PRId64") Resolved [%"PRId64"] by %s", object->getClassName(), buffer_size, ret, enc->getClassName() );
	getEncodersBase().transactionEnd();
	return ret;
 }

int64 EncoderProtocol::deserializeFrom( ISerializable* object, const char* buffer, int64 buffer_size ) {
	if ( object == NULL || buffer == NULL ) return -1;
	getEncodersBase().transactionBeginRead();
	EncoderBase* enc = selectEncoder_(getEncodersBase(), object->getClassName());
	if ( enc == NULL ) {
		getEncodersBase().transactionEnd();
		Log(LOG_CRITICAL, ":deserializeFrom(%s, %"PRId64") FAILED: Encoder not found!", object->getClassName());
		return WRET_ERR_ILLEGAL_USE;
	 }
	int64 ret = enc->deserializeFrom(object, buffer, buffer_size);
	if ( Log.isDebug() )
		Log(LOG_DEBUG, ":deserializeFrom(%s, %"PRId64") Resolved [%"PRId64"] by %s", object->getClassName(), buffer_size, ret, enc->getClassName() );
	getEncodersBase().transactionEnd();
	return ret;
 }

EncoderBase* EncoderProtocol::selectEncoder_( MapT<ObjectTypeInfo, EncoderBase*>& encoders, const char* classname, double version , bool recursive ) {
	ObjectTypeInfo info(classname, "", version, true);
	if ( encoders.exists(info) )
		return encoders.find(info);
	if ( !recursive )
		return NULL;
	std::vector<ObjectTypeInfo> class_list;
	WRESULT ret = ObjectFactory::gatherInfoOf(class_list, classname, version);
	if ( WFAILED(ret) || class_list.empty() )
		return NULL;
	std::vector<ObjectTypeInfo>::const_iterator it;
	for (it=class_list.begin(); it!=class_list.end(); ++it) {
		if ( (*it).name == info.name ) continue;
		if ( encoders.exists(*it) )
			return encoders.find(*it);
		EncoderBase* enc = selectEncoder_( encoders, (*it).name.c_str(), (*it).version, recursive );
		if ( enc != NULL )
			return enc;
	 }
	return NULL;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
WRESULT EncoderProtocol::serializeTo( const PersistenceDb* object ) {
	if ( object == NULL ) return WRET_ERR_PARAM;
	if ( object->getAdapter() == NULL ) {
		return WRET_ERR_PARAM;
	 }
	object->getAdapter()->transactionBeginRead();
	unsigned int count = object->loadItems();
	WRESULT ret = saveObjects( object->getAdapter()->getItems(), object->getFileOutput() );
	object->getAdapter()->transactionEnd();
	return ret;
 }
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

}; // namespace wosh
